#!/usr/bin/perl -w
#==========================
# Filename: mbi-gui
# Author: Joel Berger
# Author's Email: joel.a.berger <at> gmail <dot> com
# Revision Date: Nov. 14, 2009
my $VersionNumber = "1.3.0";
#
# Description: Perl script to take the .nav file from a LaTeX Beamer based presentation and create the .info file for
#              use with Impress!ve (http://impressive.sourceforge.net/).
#
#              Specifically it is intended to remove all intermediate pages from the overview and create a different 
#              transition for the new frame. It is set up to create a visually interesting but clean presentation without
#              any information of what is being displayed (i.e. no markers in the .tex file as gettransitions does). This
#              allows one to use a Beamer presentation that was not specifically created for Impress!ve.
#
# Requirements: - Perl for running the scripts (binaries will work without Perl)
#               - A presentation created in LaTeX-Beamer (http://latex-beamer.sourceforge.net/) - this script will not 
#                 work for any other presentation preparation scheme!
#               - Impress!ve for using the .info once you have it
#
# License: GPLv3 or any later version. See http://www.gnu.org/licenses/ for more information.
#
#   Copyright (C) 2009 Joel Berger
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>
#
# Change Log:
# v1.3.0: Changed "Default" transitions behavior to only select overview:off
#	  Added "Custom" transitions and selector window
#	  Began use stict compliance
#
# v1.2.0: Forked into makebeamerinfo (CLI) and mbi-gui (GUI) made with Perl/Tk
#	  Begin releasing packaged binaries using pp
#
# v1.1.3: Bugfix
#
# v1.1.2: Better regexp to find section and subsection names
#
# v1.1.1: Increased cross-platform portability
#
# v1.1:   Added Section and Subsection titles
#         Comment out $Allowed_Transititons definition to use Impress!ve default transitions
#         Added Requirements and User Definitions to header, empty command output and README
#
my $Website = 'http://code.google.com/p/makebeamerinfo/';
#==========================

# Load package to increase portability
use File::Spec::Functions;
# Load other packages
use Tk;
use strict;

############### Declare variables for MainWindow #########################
my $Use_Transitions = 1; #state of radio button - defaults to clean

############### Declare variables for CustomWindow #######################
my @trans = ( 	"Crossfade","None","PagePeel","PageTurn","SlideDown","SlideLeft",
		"SlideRight","SlideUp","SpinOutIn","SpiralOutIn","SqueezeDown","SqueezeLeft",
		"SqueezeRight","SqueezeUp","WipeBlobs","WipeCenterIn","WipeCenterOut","WipeDown",
		"WipeDownRight","WipeLeft","WipeRight","WipeUp","WipeUpLeft","ZoomOutIn" ); #list of the available transitions
my $num_trans = scalar(@trans); #calculated number of available transitions

my @On_Transitions; # array to contain enabled/disabled of the custom selected intraframe transitions
for ( my $i=0; $i < $num_trans; $i++) { # initialize custom selected intraframe transitions to all disabled
  $On_Transitions[$i] = 0;
};

my @Allowed_Transitions; # array to contain the final list of custom intraframe transitions
my $Custom_Transitions; # variable to contain the list of custom intraframe transitions to write out

# arrays for building the CustomWindow
my @labels;
my @radios;
my @checks;

# transitions for the clean scheme
my $Clean_Frame_Transition = "PageTurn";
my $Clean_Transitions = "WipeRight";

# set default custom frame transition to clean
my $Custom_Frame_Transition = $Clean_Frame_Transition;

# other variables for CustomWindow
my $max_row;
my $num_allowed;

############### Create and populate the MainWindow $mw ###################

my $mw = new MainWindow;
$mw -> title( 'Makebeamerinfo' );

#MainWindow section for selecting files
my $label_loc_nav = $mw -> Label(-text=>"Location of \".nav\" file")
	-> grid(-row=>1, -column=>1);
my $label_loc_pdf = $mw -> Label(-text=>"Location of \".pdf\" file")
	-> grid(-row=>2, -column=>1);
my $loc_nav = $mw -> Entry() 
	-> grid(-row=>1, -column=>2);
my $loc_pdf = $mw -> Entry() 
	-> grid(-row=>2, -column=>2);
my $button_get_nav = $mw -> Button(
		-text=>"Browse",
		-command =>\&getNav
		)
	-> grid(-row=>1, -column=>3);
my $button_get_pdf = $mw -> Button(
		-text=>"Browse",
		-command =>\&getPdf
		)
	-> grid(-row=>2, -column=>3);
my $button_clear_nav = $mw -> Button(-text=>"Clear",
		-command =>\&clearNav)
	-> grid(-row=>1, -column=>4);
my $button_clear_pdf = $mw -> Button(-text=>"Clear",
		-command =>\&clearPdf)
	-> grid(-row=>2, -column=>4);

#MainWindow section for selecting transition set
my $label_radio = $mw -> Label (-text=>"Frame transition set:")
	-> grid(-row=>3, -column=>1);
my $radio_default = $mw -> Radiobutton( -text=>"Default",
		-value=>"0", -variable=>\$Use_Transitions)
	->grid(-row=>3, -column=>2);
my $radio_clean = $mw -> Radiobutton( -text=>"Clean   ",
		-value=>"1", -variable=>\$Use_Transitions)
	->grid(-row=>4, -column=>2);
my $radio_custom = $mw -> Radiobutton( -text=>"Custom",
		-value=>"2", -variable=>\$Use_Transitions,
		-command=>\&openCustomWindow)
	->grid(-row=>5, -column=>2);
my $button_custom = $mw -> Button( -text=>"Select",
		-command=>\&openCustomWindow)
	->grid(-row=>5, -column=>3);

#MainWindow section for commands
my $button_execute = $mw -> Button(-text=>"Create .info",
		-command =>\&createInfo)
	->grid(-row=>6, -column=>1);
my $button_about = $mw -> Button( -text=>"About",
		-command =>\&aboutMBI)
	->grid(-row=>6, -column=>3);
my $button_exit = $mw -> Button(-text=>"Exit",
		-command =>\&exitProgram)
	->grid(-row=>6, -column=>4);

#Specify the filetypes for the two getOpenFile commands

my @nav_types = (["Nav Files", '.nav', 'TEXT'],["All Files", "*"] );

my @pdf_types = (["Pdf Files", '.pdf', 'PDF'],["All Files", "*"] );

############### MainLoop for interaction #################################
MainLoop;

sub getNav { # sub for opening a dialog to specify the .nav file and place in entry space; if possible also find .pdf

	my $Nav_Holder = $mw -> getOpenFile(-filetypes=>\@nav_types);
	unless ($Nav_Holder) { #Check that a file was selected
	  return; #Or else return unchanged
	} else { #but if specified place in $loc_nav
	  $loc_nav -> delete(0,'end');
	  $loc_nav -> insert(0,$Nav_Holder);

	  # if specified then try to find .pdf in either the same dir or the parent dir
	  my $Pdf_Test_Local;
	  my $Pdf_Test_Parent;

	  my ($Nav_Vol,$Nav_Dirs,$Nav_File) = File::Spec->splitpath("$Nav_Holder");
	  if($Nav_File =~ /([^.]+)/) {
	    my $File_Stem = $1 ;
	    my $Pdf_Test_Local_Dir = File::Spec->catpath($Nav_Vol,$Nav_Dirs);
	    $Pdf_Test_Local = catfile($Pdf_Test_Local_Dir,"$File_Stem.pdf");
	    $Pdf_Test_Parent = catfile($Pdf_Test_Local_Dir,updir,"$File_Stem.pdf");
	  };
	  if ( -e "$Pdf_Test_Local") { #if found locally
	    $loc_pdf -> delete(0,'end');
	    $loc_pdf -> insert(0,"$Pdf_Test_Local"); #place in $loc_pdf
	  } elsif ( -e "$Pdf_Test_Parent") { #if found in parent
	    $loc_pdf -> delete(0,'end');
	    $loc_pdf -> insert(0,"$Pdf_Test_Parent");#place in $loc_pdf
	  };
	};
}

sub getPdf { # sub for opening a dialog to specify the .pdf file and place in entry space
	my $Pdf_Holder = $mw -> getOpenFile(-filetypes=>\@pdf_types);
	unless ($Pdf_Holder) { #Check that a file was selected
	  return; #Or else return unchanged
	} else { #but if specified place in $loc_pdf
	  $loc_pdf -> delete(0,'end');
	  $loc_pdf -> insert(0,$Pdf_Holder);
	};
}

sub clearNav { #clear entry
	$loc_nav -> delete(0,'end');
}

sub clearPdf { #clear entry
	$loc_pdf -> delete(0,'end');
}

#sub for opening window for selecting custom transition set
sub openCustomWindow {
#  $button_custom -> select();
  my $cw = $mw -> Toplevel;
  $cw -> title ( "Create Custom Transition Set" );

  for ( my $i = 0; $i < $num_trans; $i++) {

    my $col_num;
    my $row_num;

    if ($i < $num_trans/2) {
      $row_num = $i;
      $col_num = 1;
      $max_row = $i;
    } else {
      $row_num = $i - $num_trans/2;
      $col_num = 4;
    };

    push @radios , $cw -> Radiobutton ( -variable => \$Custom_Frame_Transition , -value=>"$trans[$i]" ) -> grid(-row => $row_num , -column=> $col_num );
    push @checks , $cw -> Checkbutton ( -variable =>\$On_Transitions[$i] , -onvalue=>"1" , -offvalue=>"0" ) -> grid(-row => $row_num , -column=> ($col_num + 1) );
    push @labels , $cw -> Label ( -text=> "$trans[$i]", -width => 20) -> grid (-row => $row_num , -column => ($col_num + 2) );

  };

  my $info_1 = $cw -> Label ( -text=>"Select one frame transition\n(Radio Buttons)" ) -> grid( -row => ($max_row +1), -column => 3 );
  my $info_2 = $cw -> Label ( -text=>"And any intraframe transitions\n(Check Boxes)") -> grid( -row => ($max_row +1), -column => 6 );

  my $button_set = $cw -> Button ( -text=>"Set" , -command=> sub { grabAllowed(); destroy $cw }) -> grid( -row => ($max_row +2), -column => 3 );
  my $button_cancel = $cw -> Button ( -text=>"Cancel" , -command=> sub { destroy $cw }) -> grid( -row => ($max_row +2), -column => 6 );
}

#sub for selecting custom transition set
sub grabAllowed {
  undef(@Allowed_Transitions);
  for ( my $i = 0; $i < $num_trans; $i++ ) {
    if ( $On_Transitions[$i] == 1 ) {
      push(@Allowed_Transitions , "$trans[$i]");
    };
  };
  $num_allowed = scalar(@Allowed_Transitions);
  if ($num_allowed == 0) {
    $Custom_Transitions = "None";
  } else {
    $Custom_Transitions = join(",",@Allowed_Transitions);
  };
  $Use_Transitions = "2";
}

# Here is the meat of the action; should be mostly similar to the CLI version
sub createInfo {

	my $INPUT_NAVFILE = $loc_nav -> get();
	my $INPUT_PDFFILE = $loc_pdf -> get();

	# Check that the input file exists, then open
	unless ($INPUT_NAVFILE) {
	  $mw -> messageBox(-title=>"Error", -message=>"Please specify your \".nav\" file.\nNo .info created!");
	  return;
	} elsif (-e $INPUT_NAVFILE) {
	  open (NAVFILE, $INPUT_NAVFILE);
#	  print "Using: $INPUT_NAVFILE\n";
	} else {
	  $mw -> messageBox(-title=>"Error", -message=>"Cannot find $INPUT_NAVFILE\nNo .info created!");
	  return;
	}
	# Open .info file for writing
	unless ($INPUT_PDFFILE) {
	  $mw -> messageBox(-title=>"Error", -message=>"Please specify your \".pdf\" file.\nNo .info created!");
	  return;
	} elsif (-e $INPUT_PDFFILE) {
	  open (INFOFILE, ">$INPUT_PDFFILE.info");
	} else {
	  $mw -> messageBox(-title=>"Error", -message=>"Cannot find $INPUT_PDFFILE\nNo .info created!");
	  return;
	}

	# Lets do PageProps first
	# Initialize $Section_Number $SubSection_Number
	my $Section_Title;
	my $Section_Number = "0";
	my $SubSection_Title;
	my $SubSection_Number = "0";
	print INFOFILE "PageProps = {\n";
	while (<NAVFILE>) {
	# Find Section titles and page numbers (this queues a title waiting to be printed by making $Section_Number!=0
	  if($_ =~ m/\\sectionentry {\d+}{([^\}]+)}{(\d+)}.*/) {
	    $Section_Title = $1;
	    $Section_Number = $2;
	  }
	# Find SubSection titles and page numbers (this queues a title waiting to be printed by making $SubSection_Number!=0
	  if($_ =~ m/\@subsectionentry {\d+}{\d+}{\d+}{(\d+)}{([^\}]+)}.*/) {
	    $SubSection_Number = $1;
	    $SubSection_Title = $2;
	  }
	# Read only lines with "framepages" and get begin and end frame numbers  
	  if($_ =~ m/framepages {(\d+)}{(\d+)}/) {
	# Initialize $index for intermediate frame pages
	    my $index = $1;
	# Cycle through only intermediate frames and give them 'overview': False
	    while($index < $2) {
	      print INFOFILE "  $index:\t{\n";
	      print INFOFILE "\t  \'overview\': False,\n";
	      print INFOFILE "\t},\n";
	      $index ++;
	    }
	# For final page of frame:
	      print INFOFILE "  $2:\t{\n";
	# If there is a subsection title waiting (and by extension if there is also a section title simultaneously) to be printed then write it
	      if ($SubSection_Number != "0") {
	        print INFOFILE "\t  \'title\': \"$Section_Title: $SubSection_Title\",\n";
	# Reset $Section_Number and $Subsection_Number to 0 to reset title queue for the next frame
	        $Section_Number = "0";
	        $SubSection_Number = "0";
	      }
	# If there is still a section title waiting to be printed (alone) then write it
	      if ($Section_Number != "0") {
	        print INFOFILE "\t  \'title\': \"$Section_Title\",\n";
	# Reset $Section_Number to 0 to reset title queue for the next frame
	        $Section_Number = "0";
	      }
	# Give 'transition' property if desired
	      if ($Use_Transitions == 1) {
	        print INFOFILE "\t  \'transition\': $Clean_Frame_Transition,\n";
	        print INFOFILE "\t},\n";
	      } elsif ($Use_Transitions == 2) {
	        print INFOFILE "\t  \'transition\': $Custom_Frame_Transition,\n";
	        print INFOFILE "\t},\n";
	      } else {
	        print INFOFILE "\n\t},\n";
	      };
	  }
	}
	print INFOFILE "}\n";

	# Now lets do overall properties (if desired)
	if ($Use_Transitions == 1) { 
	  print INFOFILE "AvailableTransitions = [$Clean_Transitions]";
	} elsif ($Use_Transitions == 2) {
	  print INFOFILE "AvailableTransitions = [$Custom_Transitions]";
	};
	# Close files
	close (NAVFILE);
	close (INFOFILE);

	if (-e "$INPUT_PDFFILE.info") { #if we wrote a .info
	  $mw -> messageBox(-title=>"Goodbye", -message=>"Your .info file has been created!\nGoodbye!");
	  exit; #then inform and exit
	} else { #if not then return to main window with error dialog
#TODO check that this actually works (below)
	  $mw -> messageBox(-title=>"Error", -message=>"No .info created!\nUnknown error occured\nDo you have permissions to write to this location?");
	  return;
	}
}

sub aboutMBI {
	$mw -> messageBox(-title=>"About mbi-gui", -message=>"\n\tmbi-gui\t$VersionNumber\nPart of the makebeamerinfo suite\n\nAuthor: Joel Berger\n\nReleased under the terms of the GPLv3 or any later version\nCopyright (c) 2009 Joel Berger\n\n$Website");
}

sub exitProgram {
	$mw -> messageBox(-title=>"Goodbye", -message=>"No .info created!");
	exit;
}
